home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / tclx7.5a- / tclx7 / usr / local / tclX / 7.5a-a2 / tcl.tlib < prev    next >
Encoding:
Text File  |  1995-11-14  |  36.7 KB  |  1,466 lines

  1.  
  2. #@package: TclX-ArrayProcedures for_array_keys
  3.  
  4. proc for_array_keys {varName arrayName codeFragment} {
  5.     upvar $varName enumVar $arrayName enumArray
  6.  
  7.     if ![info exists enumArray] {
  8.     error "\"$arrayName\" isn't an array"
  9.     }
  10.  
  11.     set code 0
  12.     set result {}
  13.     set searchId [array startsearch enumArray]
  14.     while {[array anymore enumArray $searchId]} {
  15.     set enumVar [array nextelement enumArray $searchId]
  16.         set code [catch {uplevel 1 $codeFragment} result]
  17.         if {$code != 0 && $code != 4} break
  18.     }
  19.     array donesearch enumArray $searchId
  20.  
  21.     if {$code == 0 || $code == 3 || $code == 4} {
  22.         return $result
  23.     }
  24.     if {$code == 1} {
  25.         global errorCode errorInfo
  26.         return -code $code -errorcode $errorCode -errorinfo $errorInfo $result
  27.     }
  28.     return -code $code $result
  29. }
  30.  
  31. #@package: TclX-Compatibility assign_fields server_open cexpand
  32.  
  33. proc assign_fields {list args} {
  34.     if [lempty $args] {
  35.         return
  36.     }
  37.     return [uplevel lassign [list $list] $args]
  38. }
  39.  
  40. proc server_open args {
  41.     set cmd server_connect
  42.  
  43.     set buffered 1
  44.     while {[string match -* [lindex $args 0]]} {
  45.         set opt [lvarpop args]
  46.         if [cequal $opt -buf] {
  47.             set buffered 1
  48.         } elseif  [cequal $opt -nobuf] {
  49.             set buffered 0
  50.         }
  51.         lappend cmd $opt
  52.     }
  53.     if $buffered {
  54.         lappend cmd -twoids
  55.     }
  56.     set cmd [concat $cmd $args]
  57.  
  58.     uplevel $cmd
  59. }
  60.  
  61. proc cexpand str {subst -nocommands -novariables $str}
  62.  
  63. #@package: TclX-convertlib convert_lib
  64.  
  65.  
  66. proc tclx:ParseTclIndex {tclIndex fileTblVar ignore} {
  67.     upvar $fileTblVar fileTbl
  68.     set allOK 1
  69.  
  70.     # Open and validate the file.
  71.  
  72.     set tclIndexFH [open $tclIndex r]
  73.     set hdr [gets $tclIndexFH]
  74.     if {$hdr != "# Tcl autoload index file, version 2.0"} {
  75.         error "can only convert version 2.0 Tcl auto-load files"
  76.     }
  77.     set dir [file dirname $tclIndex]  ;# Expected by the script.
  78.     eval [read $tclIndexFH]
  79.     close $tclIndexFH
  80.  
  81.     foreach procName [array names auto_index] {
  82.         if ![string match "source *" $auto_index($procName)] {
  83.             puts stderr "WARNING: Can't convert load command for \"$procName\": $auto_index($procName)"
  84.             set allOK 0
  85.             continue
  86.         }
  87.         set filePath [lindex $auto_index($procName) 1]
  88.         set fileName [file tail $filePath] 
  89.         if {[lsearch $ignore $fileName] >= 0} continue
  90.  
  91.         lappend fileTbl($filePath) $procName
  92.     }
  93.     if ![info exists fileTbl] {
  94.         error "no entries could be converted in $tclIndex"
  95.     }
  96.     return $allOK
  97. }
  98.  
  99.  
  100. proc convert_lib {tclIndex packageLib {ignore {}}} {
  101.     global tclx_library
  102.     source $tclx_library/buildidx.tcl
  103.  
  104.     if {[file tail $tclIndex] != "tclIndex"} {
  105.         error "Tail file name must be `tclIndex': $tclIndex"}
  106.     if ![file readable $tclIndex] {
  107.         error "File not readable: $tclIndex"
  108.     }
  109.  
  110.     # Expand to root relative file name.
  111.  
  112.     set tclIndex [glob $tclIndex]
  113.     if ![string match "/*" $tclIndex] {
  114.         set tclIndex "[pwd]/$tclIndex"
  115.     }
  116.  
  117.     # Parse the file.
  118.  
  119.     set allOK [tclx:ParseTclIndex $tclIndex fileTbl $ignore]
  120.  
  121.     # Generate the .tlib package names with contain the directory and
  122.     # file name, less any extensions.
  123.  
  124.     if {[file extension $packageLib] != ".tlib"} {
  125.         append packageLib ".tlib"
  126.     }
  127.     set libFH [open $packageLib w]
  128.  
  129.     foreach srcFile [array names fileTbl] {
  130.         set pkgName [file tail [file dirname $srcFile]]/[file tail [file root $srcFile]]
  131.         set srcFH [open $srcFile r]
  132.         puts $libFH "#@package: $pkgName $fileTbl($srcFile)\n"
  133.         copyfile $srcFH $libFH
  134.         close $srcFH
  135.     }
  136.     close $libFH
  137.     buildpackageindex $packageLib
  138.     if !$allOK {
  139.         error "*** Not all entries converted, but library generated"
  140.     }
  141. }
  142.  
  143. #@package: TclX-developer_utils saveprocs edprocs
  144.  
  145. proc saveprocs {fileName args} {
  146.     set fp [open $fileName w]
  147.     puts $fp "# tcl procs saved on [fmtclock [getclock]]\n"
  148.     puts $fp [eval "showproc $args"]
  149.     close $fp
  150. }
  151.  
  152. proc edprocs {args} {
  153.     global env
  154.  
  155.     set tmpFilename /tmp/tcldev.[id process]
  156.  
  157.     set fp [open $tmpFilename w]
  158.     puts $fp "\n# TEMP EDIT BUFFER -- YOUR CHANGES ARE FOR THIS SESSION ONLY\n"
  159.     puts $fp [eval "showproc $args"]
  160.     close $fp
  161.  
  162.     if [info exists env(EDITOR)] {
  163.         set editor $env(EDITOR)
  164.     } else {
  165.     set editor vi
  166.     }
  167.  
  168.     set startMtime [file mtime $tmpFilename]
  169.     system "$editor $tmpFilename"
  170.  
  171.     if {[file mtime $tmpFilename] != $startMtime} {
  172.     source $tmpFilename
  173.     echo "Procedures were reloaded."
  174.     } else {
  175.     echo "No changes were made."
  176.     }
  177.     unlink $tmpFilename
  178.     return
  179. }
  180.  
  181. #@package: TclX-forfile for_file
  182.  
  183. proc for_file {var filename cmd} {
  184.     upvar $var line
  185.     set fp [open $filename r]
  186.     set code 0
  187.     set result {}
  188.     while {[gets $fp line] >= 0} {
  189.         set code [catch {uplevel 1 $cmd} result]
  190.         if {$code != 0 && $code != 4} break
  191.     }
  192.     close $fp
  193.  
  194.     if {$code == 0 || $code == 3 || $code == 4} {
  195.         return $result
  196.     }
  197.     if {$code == 1} {
  198.         global errorCode errorInfo
  199.         return -code $code -errorcode $errorCode -errorinfo $errorInfo $result
  200.     }
  201.     return -code $code $result
  202. }
  203.  
  204. #@package: TclX-globrecur recursive_glob
  205.  
  206. proc recursive_glob {dirlist globlist} {
  207.     set result {}
  208.     set recurse {}
  209.     foreach dir $dirlist {
  210.         if ![file isdirectory $dir] {
  211.             error "\"$dir\" is not a directory"
  212.         }
  213.         foreach pattern $globlist {
  214.             set result [concat $result [glob -nocomplain -- $dir/$pattern]]
  215.         }
  216.         foreach file [readdir $dir] {
  217.             set file $dir/$file
  218.             if [file isdirectory $file] {
  219.                 set fileTail [file tail $file]
  220.                 if {!(($fileTail == ".") || ($fileTail == ".."))} {
  221.                     lappend recurse $file
  222.                 }
  223.             }
  224.         }
  225.     }
  226.     if ![lempty $recurse] {
  227.         set result [concat $result [recursive_glob $recurse $globlist]]
  228.     }
  229.     return $result
  230. }
  231.  
  232. #@package: TclX-forrecur for_recursive_glob
  233.  
  234. proc for_recursive_glob {var dirlist globlist cmd {depth 1}} {
  235.     upvar $depth $var myVar
  236.     set recurse {}
  237.     foreach dir $dirlist {
  238.         if ![file isdirectory $dir] {
  239.             error "\"$dir\" is not a directory"
  240.         }
  241.         set code 0
  242.         set result {}
  243.         foreach pattern $globlist {
  244.             foreach file [glob -nocomplain -- $dir/$pattern] {
  245.                 set myVar $file
  246.                 set code [catch {uplevel $depth $cmd} result]
  247.                 if {$code != 0 && $code != 4} break
  248.             }
  249.             if {$code != 0 && $code != 4} break
  250.         }
  251.         if {$code != 0 && $code != 4} {
  252.             if {$code == 3} {
  253.                 return $result
  254.             }
  255.             if {$code == 1} {
  256.                 global errorCode errorInfo
  257.                 return -code $code -errorcode $errorCode \
  258.                         -errorinfo $errorInfo $result
  259.             }
  260.             return -code $code $result
  261.         }
  262.  
  263.         foreach file [readdir $dir] {
  264.             set file $dir/$file
  265.             if [file isdirectory $file] {
  266.                 set fileTail [file tail $file]
  267.                 if {!(($fileTail == ".") || ($fileTail == ".."))} {
  268.                     lappend recurse $file
  269.                 }
  270.             }
  271.         }
  272.     }
  273.     if ![lempty $recurse] {
  274.         return [for_recursive_glob $var $recurse $globlist $cmd \
  275.                     [expr {$depth + 1}]]
  276.     }
  277.     return {}
  278. }
  279.  
  280. #@package: TclX-help help helpcd helppwd apropos
  281.  
  282.  
  283. proc help:RootDirs {} {
  284.     global auto_path
  285.     set roots {}
  286.     foreach dir $auto_path {
  287.         if [file isdirectory $dir/help] {
  288.             lappend roots $dir/help
  289.         }
  290.     }
  291.     return $roots
  292. }
  293.  
  294.  
  295. proc help:FlattenPath pathName {
  296.     set newPath {}
  297.     foreach element [split $pathName /] {
  298.         if {"$element" == "." || [lempty $element]} continue
  299.  
  300.         if {"$element" == ".."} {
  301.             if {[llength [join $newPath /]] == 0} {
  302.                 error "Help: name goes above subject directory root" {} \
  303.                     [list TCLXHELP NAMEABOVEROOT $pathName]
  304.             }
  305.             lvarpop newPath [expr [llength $newPath]-1]
  306.             continue
  307.         }
  308.         lappend newPath $element
  309.     }
  310.     set newPath [join $newPath /]
  311.  
  312.     # Take care of the case where we started with something line "/" or "/."
  313.  
  314.     if {("$newPath" == "") && [string match "/*" $pathName]} {
  315.         set newPath "/"
  316.     }
  317.         
  318.     return $newPath
  319. }
  320.  
  321.  
  322. proc help:ConvertPath pathName {
  323.     global TCLXENV
  324.  
  325.     if {![string match "/*" $pathName]} {
  326.         if {"$TCLXENV(help:curSubject)" == "/"} {
  327.             set pathName "/$pathName"
  328.         } else {
  329.             set pathName "$TCLXENV(help:curSubject)/$pathName"
  330.         }
  331.     }
  332.     set pathName [help:FlattenPath $pathName]
  333.  
  334.     # If the virtual root is specified, return a list of directories.
  335.  
  336.     if {$pathName == "/"} {
  337.         return [help:RootDirs]
  338.     }
  339.  
  340.     # Not the virtual root find the first match.
  341.  
  342.     foreach dir [help:RootDirs] {
  343.         if [file readable $dir/$pathName] {
  344.             return [list $dir/$pathName]
  345.         }
  346.     }
  347.     error "\"$pathName\" does not exist" {} \
  348.         [list TCLXHELP NOEXIST $pathName]
  349. }
  350.  
  351.  
  352. proc help:RelativePath pathName {
  353.     foreach dir [help:RootDirs] {
  354.         if {[csubstr $pathName 0 [clength $dir]] == $dir} {
  355.             set name [csubstr $pathName [clength $dir] end]
  356.             if {$name == ""} {set name /}
  357.             return $name
  358.         }
  359.     }
  360.     if ![info exists found] {
  361.         error "problem translating \"$pathName\"" {} [list TCLXHELP INTERROR]
  362.     }
  363. }
  364.  
  365.  
  366. proc help:ListSubject {pathName pathList subjectsVar pagesVar} {
  367.     upvar $subjectsVar subjects $pagesVar pages
  368.  
  369.     set subjects {}
  370.     set pages {}
  371.     set foundDir 0
  372.     foreach dir $pathList {
  373.         if ![file isdirectory $dir] continue
  374.         set foundDir 1
  375.         foreach file [glob -nocomplain $dir/*] {
  376.             if [string match *.brf $file] continue
  377.             if [file isdirectory $file] {
  378.                 lappend subjects [file tail $file]/
  379.             } else {
  380.                 lappend pages [file tail $file]
  381.             }
  382.         }
  383.     }
  384.     if !$foundDir {
  385.         if [cequal $pathName /] {
  386.             global auto_path
  387.             error "no \"help\" directories found on auto_path ($auto_path)" {} \
  388.                 [list TCLXHELP NOHELPDIRS]
  389.         } else {
  390.             error "\"$pathName\" is not a subject" {} \
  391.                 [list TCLXHELP NOTSUBJECT $pathName]
  392.         }
  393.     }
  394.     set subjects [lsort $subjects]
  395.     set pages [lsort $pages]
  396.     return {}
  397. }
  398.  
  399.  
  400. proc help:Display line {
  401.     global TCLXENV
  402.     if {$TCLXENV(help:lineCnt) >= 23} {
  403.         set TCLXENV(help:lineCnt) 0
  404.         puts stdout ":" nonewline
  405.         flush stdout
  406.         gets stdin response
  407.         if {![lempty $response]} {
  408.             return 0}
  409.     }
  410.     puts stdout $line
  411.     incr TCLXENV(help:lineCnt)
  412. }
  413.  
  414.  
  415. proc help:DisplayPage filePath {
  416.  
  417.     set inFH [open $filePath r]
  418.     while {[gets $inFH fileBuf] >= 0} {
  419.         if {![help:Display $fileBuf]} {
  420.             break}
  421.     }
  422.     close $inFH
  423. }    
  424.  
  425.  
  426. proc help:DisplayColumns {nameList} {
  427.     set count 0
  428.     set outLine ""
  429.     foreach name $nameList {
  430.         if {$count == 0} {
  431.             append outLine "   "}
  432.         append outLine $name
  433.         if {[incr count] < 4} {
  434.             set padLen [expr 17-[clength $name]]
  435.             if {$padLen < 3} {
  436.                set padLen 3}
  437.             append outLine [replicate " " $padLen]
  438.         } else {
  439.            if {![help:Display $outLine]} {
  440.                return}
  441.            set outLine ""
  442.            set count 0
  443.         }
  444.     }
  445.     if {$count != 0} {
  446.         help:Display [string trimright $outLine]}
  447.     return
  448. }
  449.  
  450.  
  451. proc help:HelpOnHelp {} {
  452.     set helpPage [lindex [help:ConvertPath /help] 0]
  453.     if [lempty $helpPage] {
  454.         error "No help page on help found" {} \
  455.             [list TCLXHELP NOHELPPAGE]
  456.     }
  457.     help:DisplayPage $helpPage
  458. }
  459.  
  460.  
  461. proc help {{what {}}} {
  462.     global TCLXENV
  463.  
  464.     set TCLXENV(help:lineCnt) 0
  465.  
  466.     # Special case "help help", so we can get it at any level.
  467.  
  468.     if {($what == "help") || ($what == "?")} {
  469.         help:HelpOnHelp
  470.         return
  471.     }
  472.  
  473.     set pathList [help:ConvertPath $what]
  474.     if [file isfile [lindex $pathList 0]] {
  475.         help:DisplayPage [lindex $pathList 0]
  476.         return
  477.     }
  478.  
  479.     help:ListSubject $what $pathList subjects pages
  480.     set relativeDir [help:RelativePath [lindex $pathList 0]]
  481.  
  482.     if {[llength $subjects] != 0} {
  483.         help:Display "\nSubjects available in $relativeDir:"
  484.         help:DisplayColumns $subjects
  485.     }
  486.     if {[llength $pages] != 0} {
  487.         help:Display "\nHelp pages available in $relativeDir:"
  488.         help:DisplayColumns $pages
  489.     }
  490. }
  491.  
  492.  
  493.  
  494. proc helpcd {{dir /}} {
  495.     global TCLXENV
  496.  
  497.     set pathName [lindex [help:ConvertPath $dir] 0]
  498.  
  499.     if {![file isdirectory $pathName]} {
  500.         error "\"$dir\" is not a subject" \
  501.             [list TCLXHELP NOTSUBJECT $dir]
  502.     }
  503.  
  504.     set TCLXENV(help:curSubject) [help:RelativePath $pathName]
  505.     return
  506. }
  507.  
  508.  
  509. proc helppwd {} {
  510.         global TCLXENV
  511.         echo "Current help subject: $TCLXENV(help:curSubject)"
  512. }
  513.  
  514.  
  515. proc apropos {regexp} {
  516.     global TCLXENV
  517.  
  518.     set TCLXENV(help:lineCnt) 0
  519.  
  520.     set ch [scancontext create]
  521.     scanmatch -nocase $ch $regexp {
  522.         set path [lindex $matchInfo(line) 0]
  523.         set desc [lrange $matchInfo(line) 1 end]
  524.         if {![help:Display [format "%s - %s" $path $desc]]} {
  525.             set stop 1
  526.             return}
  527.     }
  528.     set stop 0
  529.     foreach dir [help:RootDirs] {
  530.         foreach brief [glob -nocomplain $dir/*.brf] {
  531.             set briefFH [open $brief]
  532.             scanfile $ch $briefFH
  533.             close $briefFH
  534.             if $stop break
  535.         }
  536.         if $stop break
  537.     }
  538.     scancontext delete $ch
  539. }
  540.  
  541. global TCLXENV
  542.  
  543. set TCLXENV(help:curSubject) "/"
  544.  
  545. #@package: TclX-profrep profrep
  546.  
  547. proc profrep:sortcmp {key1 key2} {
  548.     upvar profData profData keyIndex keyIndex
  549.     
  550.     set val1 [lindex $profData($key1) $keyIndex]
  551.     set val2 [lindex $profData($key2) $keyIndex]
  552.  
  553.     if {$val1 < $val2} {
  554.         return -1
  555.     }
  556.     if {$val1 > $val2} {
  557.         return 1
  558.     }
  559.     return 0
  560. }
  561.  
  562. proc profrep:sort {profDataVar sortKey} {
  563.     upvar $profDataVar profData
  564.  
  565.     case $sortKey {
  566.         {calls} {set keyIndex 0}
  567.         {real}  {set keyIndex 1}
  568.         {cpu}   {set keyIndex 2}
  569.         default {
  570.             error "Expected a sort type of: `calls', `cpu' or ` real'"
  571.         }
  572.     }
  573.  
  574.     return [lsort -integer -decreasing -command profrep:sortcmp \
  575.             [array names profData]]
  576. }
  577.  
  578. proc profrep:print {profDataVar sortedProcList outFile userTitle} {
  579.     upvar $profDataVar profData
  580.     
  581.     set maxNameLen 0
  582.     foreach procStack [array names profData] {
  583.         foreach procName $procStack {
  584.             set maxNameLen [max $maxNameLen [clength $procName]]
  585.         }
  586.     }
  587.  
  588.     if {$outFile == ""} {
  589.         set outFH stdout
  590.     } else {
  591.         set outFH [open $outFile w]
  592.     }
  593.  
  594.     # Output a header.
  595.  
  596.     set stackTitle "Procedure Call Stack"
  597.     set maxNameLen [max [expr $maxNameLen+6] [expr [clength $stackTitle]+4]]
  598.     set hdr [format "%-${maxNameLen}s %10s %10s %10s" $stackTitle \
  599.                     "Calls" "Real Time" "CPU Time"]
  600.     if {$userTitle != ""} {
  601.         puts $outFH [replicate - [clength $hdr]]
  602.         puts $outFH $userTitle
  603.     }
  604.     puts $outFH [replicate - [clength $hdr]]
  605.     puts $outFH $hdr
  606.     puts $outFH [replicate - [clength $hdr]]
  607.  
  608.     # Output the data in sorted order.
  609.  
  610.     foreach procStack $sortedProcList {
  611.         set data $profData($procStack)
  612.         puts $outFH [format "%-${maxNameLen}s %10d %10d %10d" \
  613.                             [lvarpop procStack] \
  614.                             [lindex $data 0] [lindex $data 1] [lindex $data 2]]
  615.         foreach procName $procStack {
  616.             if {$procName == "<global>"} break
  617.             puts $outFH "    $procName"
  618.         }
  619.     }
  620.     if {$outFile != ""} {
  621.         close $outFH
  622.     }
  623. }
  624.  
  625.  
  626. proc profrep {profDataVar sortKey {outFile {}} {userTitle {}}} {
  627.     upvar $profDataVar profData
  628.  
  629.     set sortedProcList [profrep:sort profData $sortKey]
  630.     profrep:print profData $sortedProcList $outFile $userTitle
  631.  
  632. }
  633.  
  634. #@package: TclX-directory_stack pushd popd dirs
  635.  
  636. global TCLXENV(dirPushList)
  637.  
  638. set TCLXENV(dirPushList) ""
  639.  
  640. proc pushd {{new ""}} {
  641.     global TCLXENV
  642.  
  643.     set current [pwd]
  644.     if {[clength $new] > 0} {
  645.         set dirs [glob -nocomplain $new]
  646.         set count [llength $dirs]
  647.         if {$count == 0} {
  648.             error "no such directory: $new"
  649.         } elseif {$count != 1} {
  650.             error "ambiguous directory: $new: [join $directories ", "]"
  651.         }
  652.         cd [lindex $dirs 0]
  653.         lvarpush TCLXENV(dirPushList) $current
  654.     } else {
  655.         if [lempty $TCLXENV(dirPushList)] {
  656.             error "directory stack empty"
  657.         }
  658.         cd [lindex $TCLXENV(dirPushList) 0]
  659.         lvarpop TCLXENV(dirPushList)
  660.         lvarpush TCLXENV(dirPushList) $current
  661.     }
  662.     return [pwd]
  663. }
  664.  
  665. proc popd {} {
  666.     global TCLXENV
  667.  
  668.     if [lempty $TCLXENV(dirPushList)] {
  669.         error "directory stack empty"
  670.     }
  671.     cd [lvarpop TCLXENV(dirPushList)]
  672.     return [pwd]
  673. }
  674.  
  675. proc dirs {} { 
  676.     global TCLXENV
  677.     return [concat [list [pwd]] $TCLXENV(dirPushList)]
  678. }
  679.  
  680. #@package: TclX-set_functions union intersect intersect3 lrmdups
  681.  
  682. proc union {lista listb} {
  683.     return [lrmdups [concat $lista $listb]]
  684. }
  685.  
  686. proc lrmdups list {
  687.     if [lempty $list] {
  688.         return {}
  689.     }
  690.     set list [lsort $list]
  691.     set last [lvarpop list]
  692.     lappend result $last
  693.     foreach element $list {
  694.     if ![cequal $last $element] {
  695.         lappend result $element
  696.         set last $element
  697.     }
  698.     }
  699.     return $result
  700. }
  701.  
  702.  
  703. proc intersect3 {list1 list2} {
  704.     set list1Result ""
  705.     set list2Result ""
  706.     set intersectList ""
  707.  
  708.     set list1 [lrmdups $list1]
  709.     set list2 [lrmdups $list2]
  710.  
  711.     while {1} {
  712.         if [lempty $list1] {
  713.             if ![lempty $list2] {
  714.                 set list2Result [concat $list2Result $list2]
  715.             }
  716.             break
  717.         }
  718.         if [lempty $list2] {
  719.         set list1Result [concat $list1Result $list1]
  720.             break
  721.         }
  722.         set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
  723.  
  724.         if {$compareResult < 0} {
  725.             lappend list1Result [lvarpop list1]
  726.             continue
  727.         }
  728.         if {$compareResult > 0} {
  729.             lappend list2Result [lvarpop list2]
  730.             continue
  731.         }
  732.         lappend intersectList [lvarpop list1]
  733.         lvarpop list2
  734.     }
  735.     return [list $list1Result $intersectList $list2Result]
  736. }
  737.  
  738. proc intersect {list1 list2} {
  739.     set intersectList ""
  740.  
  741.     set list1 [lsort $list1]
  742.     set list2 [lsort $list2]
  743.  
  744.     while {1} {
  745.         if {[lempty $list1] || [lempty $list2]} break
  746.  
  747.         set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
  748.  
  749.         if {$compareResult < 0} {
  750.             lvarpop list1
  751.             continue
  752.         }
  753.  
  754.         if {$compareResult > 0} {
  755.             lvarpop list2
  756.             continue
  757.         }
  758.  
  759.         lappend intersectList [lvarpop list1]
  760.         lvarpop list2
  761.     }
  762.     return $intersectList
  763. }
  764.  
  765.  
  766.  
  767. #@package: TclX-showproc showproc
  768.  
  769. proc showproc args {
  770.     if [lempty $args] {
  771.         set args [info procs]
  772.     }
  773.     set out {}
  774.  
  775.     foreach procname $args {
  776.         if [lempty [info procs $procname]] {
  777.             auto_load $procname
  778.         }
  779.         set arglist [info args $procname]
  780.         set nargs {}
  781.         while {[llength $arglist] > 0} {
  782.             set varg [lvarpop arglist 0]
  783.             if [info default $procname $varg defarg] {
  784.                 lappend nargs [list $varg $defarg]
  785.             } else {
  786.                 lappend nargs $varg
  787.             }
  788.         }
  789.         append out "proc $procname [list $nargs] \{[info body $procname]\}\n"
  790.     }
  791.     return $out
  792. }
  793.  
  794. #@package: TclX-stringfile_functions read_file write_file
  795.  
  796. proc read_file {fileName args} {
  797.     if {$fileName == "-nonewline"} {
  798.         set flag $fileName
  799.         set fileName [lvarpop args]
  800.     } else {
  801.         set flag {}
  802.     }
  803.     set fp [open $fileName]
  804.     set stat [catch {
  805.         eval read $flag $fp $args
  806.     } result]
  807.     close $fp
  808.     if {$stat != 0} {
  809.         global errorInfo errorCode
  810.         error $result $errorInfo $errorCode
  811.     }
  812.     return $result
  813.  
  814. proc write_file {fileName args} {
  815.     set fp [open $fileName w]
  816.     
  817.     set stat [catch {
  818.         foreach string $args {
  819.             puts $fp $string
  820.         }
  821.     } result]
  822.     close $fp
  823.     if {$stat != 0} {
  824.         global errorInfo errorCode
  825.         error $result $errorInfo $errorCode
  826.     }
  827. }
  828.  
  829.  
  830. #@package: TclX-libraries searchpath auto_load_file
  831.  
  832. proc searchpath {pathlist file} {
  833.     foreach dir $pathlist {
  834.         if {$dir == ""} {set dir .}
  835.         if {[catch {file exists $dir/$file} result] == 0 && $result}  {
  836.             return $dir/$file
  837.         }
  838.     }
  839.     return {}
  840. }
  841.  
  842. proc auto_load_file {name} {
  843.     global auto_path errorCode
  844.     if {[string first / $name] >= 0} {
  845.         return  [uplevel 1 source $name]
  846.     }
  847.     set where [searchpath $auto_path $name]
  848.     if [lempty $where] {
  849.         error "couldn't find $name in any directory in auto_path"
  850.     }
  851.     uplevel 1 source $where
  852. }
  853.  
  854. #@package: TclX-lib-list auto_packages auto_commands
  855.  
  856.  
  857. proc auto_packages {{option {}}} {
  858.     global auto_pkg_index
  859.  
  860.     auto_load  ;# Make sure all indexes are loaded.
  861.     if ![info exists auto_pkg_index] {
  862.         return {}
  863.     }
  864.     
  865.     set packList [array names auto_pkg_index] 
  866.     if [lempty $option] {
  867.         return $packList
  868.     }
  869.  
  870.     if {$option != "-files"} {
  871.         error "Unknow option \"$option\", expected \"-files\""
  872.     }
  873.     set locList {}
  874.     foreach pack $packList {
  875.         lappend locList [list $pack [lindex $auto_pkg_index($pack) 0]]
  876.     }
  877.     return $locList
  878. }
  879.  
  880.  
  881. proc auto_commands {{option {}}} {
  882.     global auto_index
  883.  
  884.     auto_load  ;# Make sure all indexes are loaded.
  885.     if ![info exists auto_index] {
  886.         return {}
  887.     }
  888.     
  889.     set cmdList [array names auto_index] 
  890.     if [lempty $option] {
  891.         return $cmdList
  892.     }
  893.  
  894.     if {$option != "-loaders"} {
  895.         error "Unknow option \"$option\", expected \"-loaders\""
  896.     }
  897.     set loadList {}
  898.     foreach cmd $cmdList {
  899.         lappend loadList [list $cmd $auto_index($cmd)]
  900.     }
  901.     return $loadList
  902. }
  903.  
  904. #@package: TclX-ucblib auto_reset auto_mkindex
  905.  
  906.  
  907. proc auto_reset {} {
  908.     global auto_execs auto_index auto_oldpath
  909.     foreach p [info procs] {
  910.     if {[info exists auto_index($p)] && ($p != "unknown")
  911.         && ![string match auto_* $p]} {
  912.         rename $p {}
  913.     }
  914.     }
  915.     catch {unset auto_execs}
  916.     catch {unset auto_index}
  917.     catch {unset auto_oldpath}
  918.     # *** TclX ***
  919.     global auto_pkg_index tclx_library
  920.     catch {unset auto_pkg_index}
  921.     set auto_index(buildpackageindex) {source $tclx_library/buildidx.tcl}
  922.     return
  923. }
  924.  
  925.  
  926. proc auto_mkindex {dir args} {
  927.     global errorCode errorInfo
  928.     set oldDir [pwd]
  929.     cd $dir
  930.     set dir [pwd]
  931.     append index "# Tcl autoload index file, version 2.0\n"
  932.     append index "# This file is generated by the \"auto_mkindex\" command\n"
  933.     append index "# and sourced to set up indexing information for one or\n"
  934.     append index "# more commands.  Typically each line is a command that\n"
  935.     append index "# sets an element in the auto_index array, where the\n"
  936.     append index "# element name is the name of a command and the value is\n"
  937.     append index "# a script that loads the command.\n\n"
  938.     foreach file [eval glob $args] {
  939.     set f ""
  940.     set error [catch {
  941.         set f [open $file]
  942.         while {[gets $f line] >= 0} {
  943.         if [regexp {^proc[     ]+([^     ]*)} $line match procName] {
  944.             append index "set [list auto_index($procName)]"
  945.             append index " \"source \$dir/$file\"\n"
  946.         }
  947.         }
  948.         close $f
  949.     } msg]
  950.     if $error {
  951.         set code $errorCode
  952.         set info $errorInfo
  953.         catch {close $f}
  954.         cd $oldDir
  955.         error $msg $info $code
  956.     }
  957.     }
  958.     set f [open tclIndex w]
  959.     puts $f $index nonewline
  960.     close $f
  961.     cd $oldDir
  962. }
  963.  
  964. #@package: TclX-fmath acos asin atan ceil cos cosh exp fabs floor log log10 \
  965.            sin sinh sqrt tan tanh fmod pow atan2 abs double int round
  966.  
  967. proc acos  x {uplevel [list expr acos($x)]}
  968. proc asin  x {uplevel [list expr asin($x)]}
  969. proc atan  x {uplevel [list expr atan($x)]}
  970. proc ceil  x {uplevel [list expr ceil($x)]}
  971. proc cos   x {uplevel [list expr cos($x)]}
  972. proc cosh  x {uplevel [list expr cosh($x)]}
  973. proc exp   x {uplevel [list expr exp($x)]}
  974. proc fabs  x {uplevel [list expr abs($x)]}
  975. proc floor x {uplevel [list expr floor($x)]}
  976. proc log   x {uplevel [list expr log($x)]}
  977. proc log10 x {uplevel [list expr log10($x)]}
  978. proc sin   x {uplevel [list expr sin($x)]}
  979. proc sinh  x {uplevel [list expr sinh($x)]}
  980. proc sqrt  x {uplevel [list expr sqrt($x)]}
  981. proc tan   x {uplevel [list expr tan($x)]}
  982. proc tanh  x {uplevel [list expr tanh($x)]}
  983.  
  984. proc fmod {x n} {uplevel [list expr fmod($x,$n)]}
  985. proc pow {x n} {uplevel [list expr pow($x,$n)]}
  986.  
  987.  
  988. proc atan2  x {uplevel [list expr atan2($x)]}
  989. proc abs    x {uplevel [list expr abs($x)]}
  990. proc double x {uplevel [list expr double($x)]}
  991. proc int    x {uplevel [list expr int($x)]}
  992. proc round  x {uplevel [list expr round($x)]}
  993.  
  994.  
  995. #@package: TclX-shell tclx_unknown2 auto_execok
  996.  
  997.  
  998. proc tclx_unknown2 cmd {
  999.     global tcl_interactive auto_noexec
  1000.  
  1001.     set name [lindex $cmd 0]
  1002.  
  1003.     if ![info exists auto_noexec] {
  1004.         if [auto_execok $name] {
  1005.             if {!$tcl_interactive || [info level] > 2 || [info script] != ""} {
  1006.                 return [list return -code error "Auto execution of Unix commands only supported as interactive commands.\nUse \"exec\" to execute \"$name\""]
  1007.             }
  1008.             return [list eval [list system $cmd] {;} concat]
  1009.         }
  1010.     }
  1011.  
  1012.     if {!$tcl_interactive || ([info level] > 2) || [info script] != ""} {
  1013.         return [list  return -code error "invalid command name \"$name\""]
  1014.     }
  1015.  
  1016.     # csh-style redo.
  1017.  
  1018.     if {([info level] == 2) && ([info script] == "")} {
  1019.         if {$name == "!!"} {
  1020.             return {history redo}
  1021.         }
  1022.         if [regexp {^!(.+)$} $name dummy event] {
  1023.             return [list history redo $event]
  1024.         }
  1025.         if [regexp {^\^([^^]*)\^([^^]*)\^?$} $name dummy old new] {
  1026.             return [list history substitute $old $new]
  1027.         }
  1028.         set cmds [info commands $name*]
  1029.         if {[llength $cmds] == 1} {
  1030.             return [lreplace $cmd 0 0 $cmds]
  1031.         }
  1032.         if {[llength $cmds] != 0} {
  1033.             if {$name == ""} {
  1034.                 return [list return -code error "empty command name \"\""]
  1035.             } else {
  1036.                 return [list return -code error \
  1037.                         "ambiguous command name \"$name\": [lsort $cmds]"]
  1038.             }
  1039.         }
  1040.     }
  1041.     return [list return -code error "invalid command name \"$name\""]
  1042. }
  1043.  
  1044.  
  1045.  
  1046. proc auto_execok name {
  1047.     global auto_execs env
  1048.  
  1049.     if [info exists auto_execs($name)] {
  1050.         return $auto_execs($name)
  1051.     }
  1052.     set auto_execs($name) 0
  1053.     if {[string first / $name] >= 0} {
  1054.     if {[file executable $name] && ![file isdirectory $name]} {
  1055.         set auto_execs($name) 1
  1056.     }
  1057.     return $auto_execs($name)
  1058.     }
  1059.     foreach dir [split $env(PATH) :] {
  1060.         if {[file executable $dir/$name] && ![file isdirectory $dir/$name]} {
  1061.             set auto_execs($name) 1
  1062.             return 1
  1063.         }
  1064.     }
  1065.     return 0
  1066. }
  1067.  
  1068. #@package: TclX-buildhelp buildhelp
  1069.  
  1070. proc TruncFileName {pathName} {
  1071.     global truncFileNames
  1072.  
  1073.     if {!$truncFileNames} {
  1074.         return $pathName}
  1075.     set fileName [file tail $pathName]
  1076.     if {"[crange $fileName 0 3]" == "Tcl_"} {
  1077.         set fileName [crange $fileName 4 end]}
  1078.     set fileName [crange $fileName 0 13]
  1079.     return "[file dirname $pathName]/$fileName"
  1080. }
  1081.  
  1082.  
  1083. proc EnsureDirs {filePath} {
  1084.     set dirPath [file dirname $filePath]
  1085.     if [file exists $dirPath] return
  1086.     foreach dir [split $dirPath /] {
  1087.         lappend dirList $dir
  1088.         set partPath [join $dirList /]
  1089.         if [file exists $partPath] continue
  1090.  
  1091.         mkdir $partPath
  1092.         chmod u=rwx,go=rx $partPath
  1093.     }
  1094. }
  1095.  
  1096.  
  1097. proc CreateFilterNroffManPageContext {} {
  1098.     global filterNroffManPageContext
  1099.  
  1100.     set filterNroffManPageContext [scancontext create]
  1101.  
  1102.     # On finding a page header, drop the previous line (which is
  1103.     # the page footer). Also deleting the blank lines followin
  1104.     # the last line on the previous page.
  1105.  
  1106.     scanmatch $filterNroffManPageContext {@@@BUILDHELP@@@} {
  1107.         catch {unset prev2Blanks}
  1108.         catch {unset prev1Line}
  1109.         catch {unset prev1Blanks}
  1110.         set nukeBlanks {}
  1111.     }
  1112.  
  1113.     # Save blank lines
  1114.  
  1115.     scanmatch $filterNroffManPageContext {$^} {
  1116.         if ![info exists nukeBlanks] {
  1117.             append prev1Blanks \n
  1118.         }
  1119.     }
  1120.  
  1121.     # Non-blank line, save it.  Output the 2nd previous line if necessary.
  1122.  
  1123.     scanmatch $filterNroffManPageContext {
  1124.         catch {unset nukeBlanks}
  1125.         if [info exists prev2Line] {
  1126.             puts $outFH $prev2Line
  1127.             unset prev2Line
  1128.         }
  1129.         if [info exists prev2Blanks] {
  1130.             puts $outFH $prev2Blanks nonewline
  1131.             unset prev2Blanks
  1132.         }
  1133.         if [info exists prev1Line] {
  1134.             set prev2Line $prev1Line
  1135.         }
  1136.         set prev1Line $matchInfo(line)
  1137.         if [info exists prev1Blanks] {
  1138.             set prev2Blanks $prev1Blanks
  1139.             unset prev1Blanks
  1140.         }
  1141.     }
  1142. }
  1143.  
  1144.  
  1145. proc FilterNroffManPage {inFH outFH} {
  1146.     global filterNroffManPageContext
  1147.  
  1148.     if ![info exists filterNroffManPageContext] {
  1149.         CreateFilterNroffManPageContext
  1150.     }
  1151.  
  1152.     scanfile $filterNroffManPageContext $inFH
  1153.  
  1154.     if [info exists prev2Line] {
  1155.         puts $outFH $prev2Line
  1156.     }
  1157. }
  1158.  
  1159.  
  1160. proc CreateExtractNroffHeaderContext {} {
  1161.     global extractNroffHeaderContext
  1162.  
  1163.     set extractNroffHeaderContext [scancontext create]
  1164.  
  1165.     scanmatch $extractNroffHeaderContext {'\\"@endheader[     ]*$} {
  1166.         break
  1167.     }
  1168.     scanmatch $extractNroffHeaderContext {'\\"@:} {
  1169.         append nroffHeader "[crange $matchInfo(line) 5 end]\n"
  1170.     }
  1171.     scanmatch $extractNroffHeaderContext {
  1172.         append nroffHeader "$matchInfo(line)\n"
  1173.     }
  1174. }
  1175.  
  1176.  
  1177. proc ExtractNroffHeader {manPageFH} {
  1178.     global extractNroffHeaderContext nroffHeader
  1179.  
  1180.     if ![info exists extractNroffHeaderContext] {
  1181.         CreateExtractNroffHeaderContext
  1182.     }
  1183.     scanfile $extractNroffHeaderContext $manPageFH
  1184. }
  1185.  
  1186.  
  1187.  
  1188. proc CreateExtractNroffHelpContext {} {
  1189.     global extractNroffHelpContext
  1190.  
  1191.     set extractNroffHelpContext [scancontext create]
  1192.  
  1193.     scanmatch $extractNroffHelpContext {^'\\"@endhelp[     ]*$} {
  1194.         break
  1195.     }
  1196.  
  1197.     scanmatch $extractNroffHelpContext {^'\\"@brief:} {
  1198.         if $foundBrief {
  1199.             error {Duplicate "@brief:" entry}
  1200.         }
  1201.         set foundBrief 1
  1202.         puts $briefHelpFH "$helpName\t[csubstr $matchInfo(line) 11 end]"
  1203.         continue
  1204.     }
  1205.  
  1206.     scanmatch $extractNroffHelpContext {^'\\"@:} {
  1207.         puts $nroffFH  [csubstr $matchInfo(line) 5 end]
  1208.         continue
  1209.     }
  1210.     scanmatch $extractNroffHelpContext {^'\\"@help:} {
  1211.         error {"@help" found within another help section"}
  1212.     }
  1213.     scanmatch $extractNroffHelpContext {
  1214.         puts $nroffFH $matchInfo(line)
  1215.     }
  1216. }
  1217.  
  1218.  
  1219. proc ExtractNroffHelp {manPageFH manLine} {
  1220.     global helpDir nroffHeader briefHelpFH colArgs
  1221.     global extractNroffHelpContext
  1222.  
  1223.     if ![info exists extractNroffHelpContext] {
  1224.         CreateExtractNroffHelpContext
  1225.     }
  1226.  
  1227.     set helpName [string trim [csubstr $manLine 9 end]]
  1228.     set helpFile [TruncFileName "$helpDir/$helpName"]
  1229.     if [file exists $helpFile] {
  1230.         error "Help file already exists: $helpFile"
  1231.     }
  1232.     EnsureDirs $helpFile
  1233.  
  1234.     set tmpFile "[file dirname $helpFile]/tmp.[id process]"
  1235.  
  1236.     echo "    creating help file $helpName"
  1237.  
  1238.     set nroffFH [open "| nroff -man | col $colArgs > $tmpFile" w]
  1239.  
  1240.     puts $nroffFH {.TH @@@BUILDHELP@@@ 1}
  1241.  
  1242.     set foundBrief 0
  1243.     scanfile $extractNroffHelpContext $manPageFH
  1244.  
  1245.     # Close returns an error on if anything comes back on stderr, even if
  1246.     # its a warning.  Output errors and continue.
  1247.  
  1248.     set stat [catch {
  1249.         close $nroffFH
  1250.     } msg]
  1251.     if $stat {
  1252.         puts stderr "nroff: $msg"
  1253.     }
  1254.  
  1255.     set tmpFH [open $tmpFile r]
  1256.     set helpFH [open $helpFile w]
  1257.  
  1258.     FilterNroffManPage $tmpFH $helpFH
  1259.  
  1260.     close $tmpFH
  1261.     close $helpFH
  1262.  
  1263.     unlink $tmpFile
  1264.     chmod a-w,a+r $helpFile
  1265. }
  1266.  
  1267.  
  1268. proc CreateExtractScriptHelpContext {} {
  1269.     global extractScriptHelpContext
  1270.  
  1271.     set extractScriptHelpContext [scancontext create]
  1272.  
  1273.     scanmatch $extractScriptHelpContext {^#@endhelp[     ]*$} {
  1274.         break
  1275.     }
  1276.  
  1277.     scanmatch $extractScriptHelpContext {^#@brief:} {
  1278.         if $foundBrief {
  1279.             error {Duplicate "@brief" entry}
  1280.         }
  1281.         set foundBrief 1
  1282.         puts $briefHelpFH "$helpName\t[csubstr $matchInfo(line) 9 end]"
  1283.         continue
  1284.     }
  1285.  
  1286.     scanmatch $extractScriptHelpContext {^#@help:} {
  1287.         error {"@help" found within another help section"}
  1288.     }
  1289.  
  1290.     scanmatch $extractScriptHelpContext {^#$} {
  1291.         puts $helpFH ""
  1292.     }
  1293.  
  1294.     scanmatch $extractScriptHelpContext {
  1295.         if {[clength $matchInfo(line)] > 1} {
  1296.             puts $helpFH " [csubstr $matchInfo(line) 1 end]"
  1297.         } else {
  1298.             puts $helpFH $matchInfo(line)
  1299.         }
  1300.     }
  1301. }
  1302.  
  1303.  
  1304. proc ExtractScriptHelp {scriptPageFH scriptLine} {
  1305.     global helpDir briefHelpFH
  1306.     global extractScriptHelpContext
  1307.  
  1308.     if ![info exists extractScriptHelpContext] {
  1309.         CreateExtractScriptHelpContext
  1310.     }
  1311.  
  1312.     set helpName [string trim [csubstr $scriptLine 7 end]]
  1313.     set helpFile "$helpDir/$helpName"
  1314.     if {[file exists $helpFile]} {
  1315.         error "Help file already exists: $helpFile"
  1316.     }
  1317.     EnsureDirs $helpFile
  1318.  
  1319.     echo "    creating help file $helpName"
  1320.  
  1321.     set helpFH [open $helpFile w]
  1322.  
  1323.     set foundBrief 0
  1324.     scanfile $extractScriptHelpContext $scriptPageFH
  1325.  
  1326.     close $helpFH
  1327.     chmod a-w,a+r $helpFile
  1328. }
  1329.  
  1330.  
  1331. proc ProcessNroffFile {pathName} {
  1332.    global nroffScanCT scriptScanCT nroffHeader
  1333.  
  1334.    set fileName [file tail $pathName]
  1335.  
  1336.    set nroffHeader {}
  1337.    set manPageFH [open $pathName r]
  1338.    set matchInfo(fileName) [file tail $pathName]
  1339.  
  1340.    echo "    scanning $pathName"
  1341.  
  1342.    scanfile $nroffScanCT $manPageFH
  1343.  
  1344.    close $manPageFH
  1345. }
  1346.  
  1347.  
  1348. proc ProcessTclScript {pathName} {
  1349.    global scriptScanCT nroffHeader
  1350.  
  1351.    set scriptFH [open "$pathName" r]
  1352.    set matchInfo(fileName) [file tail $pathName]
  1353.  
  1354.    echo "    scanning $pathName"
  1355.    scanfile $scriptScanCT $scriptFH
  1356.  
  1357.    close $scriptFH
  1358. }
  1359.  
  1360.  
  1361. proc buildhelp {helpDirPath briefFile sourceFiles} {
  1362.     global helpDir truncFileNames nroffScanCT
  1363.     global scriptScanCT briefHelpFH colArgs
  1364.  
  1365.     echo ""
  1366.     echo "Begin building help tree"
  1367.  
  1368.     # Determine version of col command to use (no -x on BSD)
  1369.     if {[system {col -bx </dev/null >/dev/null 2>&1}] != 0} {
  1370.         set colArgs {-b}
  1371.     } else {
  1372.         set colArgs {-bx}
  1373.     }
  1374.     set helpDir $helpDirPath
  1375.     if {![file exists $helpDir]} {
  1376.         mkdir $helpDir
  1377.     }
  1378.  
  1379.     if {![file isdirectory $helpDir]} {
  1380.         error [concat "$helpDir is not a directory or does not exist. "  
  1381.                       "This should be the help root directory"]
  1382.     }
  1383.         
  1384.     set status [catch {set tmpFH [open $helpDir/AVeryVeryBigFileName w]}]
  1385.     if {$status != 0} {
  1386.         set truncFileNames 1
  1387.     } else {
  1388.         close $tmpFH
  1389.         unlink $helpDir/AVeryVeryBigFileName
  1390.         set truncFileNames 0
  1391.     }
  1392.  
  1393.     set nroffScanCT [scancontext create]
  1394.  
  1395.     scanmatch $nroffScanCT {'\\"@help:} {
  1396.         ExtractNroffHelp $matchInfo(handle) $matchInfo(line)
  1397.         continue
  1398.     }
  1399.  
  1400.     scanmatch $nroffScanCT {^'\\"@header} {
  1401.         ExtractNroffHeader $matchInfo(handle)
  1402.         continue
  1403.     }
  1404.     scanmatch $nroffScanCT {^'\\"@endhelp} {
  1405.         error [concat {@endhelp" without corresponding "@help:"} \
  1406.                  ", offset = $matchInfo(offset)"]
  1407.     }
  1408.     scanmatch $nroffScanCT {^'\\"@brief} {
  1409.         error [concat {"@brief" without corresponding "@help:"} \
  1410.                  ", offset = $matchInfo(offset)"]
  1411.     }
  1412.  
  1413.     set scriptScanCT [scancontext create]
  1414.     scanmatch $scriptScanCT {^#@help:} {
  1415.         ExtractScriptHelp $matchInfo(handle) $matchInfo(line)
  1416.     }
  1417.  
  1418.     if {[file extension $briefFile] != ".brf"} {
  1419.         error "Brief file \"$briefFile\" must have an extension \".brf\""
  1420.     }
  1421.     if [file exists $helpDir/$briefFile] {
  1422.         error "Brief file \"$helpDir/$briefFile\" already exists"
  1423.     }
  1424.     set briefHelpFH [open "|sort > $helpDir/$briefFile" w]
  1425.  
  1426.     foreach manFile [glob $sourceFiles] {
  1427.         set ext [file extension $manFile]
  1428.         if {$ext == ".tcl" || $ext == ".tlib"} {
  1429.             set status [catch {ProcessTclScript $manFile} msg]
  1430.         } else {
  1431.             set status [catch {ProcessNroffFile $manFile} msg]
  1432.         }
  1433.         if {$status != 0} {
  1434.             global errorInfo errorCode
  1435.             error "Error extracting help from: $manFile" $errorInfo $errorCode
  1436.         }
  1437.     }
  1438.  
  1439.     close $briefHelpFH
  1440.     chmod a-w,a+r $helpDir/$briefFile
  1441.     echo "Completed extraction of help files"
  1442. }
  1443.  
  1444.  
  1445. #@package: Tcl-parray parray
  1446.  
  1447.  
  1448. proc parray {a {pattern *}} {
  1449.     upvar 1 $a array
  1450.     if ![array exists array] {
  1451.     error "\"$a\" isn't an array"
  1452.     }
  1453.     set maxl 0
  1454.     foreach name [lsort [array names array $pattern]] {
  1455.     if {[string length $name] > $maxl} {
  1456.         set maxl [string length $name]
  1457.     }
  1458.     }
  1459.     set maxl [expr {$maxl + [string length $a] + 2}]
  1460.     foreach name [lsort [array names array $pattern]] {
  1461.     set nameString [format %s(%s) $a $name]
  1462.     puts stdout [format "%-*s = %s" $maxl $nameString $array($name)]
  1463.     }
  1464. }
  1465.